package de.tsajar.es.arrow;

import com.jme3.app.Application;
import com.jme3.app.state.AppStateManager;
import com.jme3.collision.CollisionResult;
import com.jme3.collision.CollisionResults;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Ray;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import com.simsilica.es.Entity;
import com.simsilica.es.EntityId;
import com.simsilica.es.EntitySet;
import de.tsajar.es.EntitySystemAppState;
import de.tsajar.es.physics.SolidComponent;
import de.tsajar.es.physics.VelocityComponent;
import de.tsajar.es.position.PositionComponent;
import de.tsajar.es.position.RotationComponent;

/**
 *
 * @author Eike Foede
 */
public class ArrowSystem extends EntitySystemAppState {

    private EntitySet entities;
    private Node collisionNode;
    private Vector3f gravity = new Vector3f(0, -9.81f, 0);
    private float rotCount = 0;

    public Vector3f getGravity() {
        return gravity;
    }

    public void setGravity(Vector3f gravity) {
        this.gravity = gravity;
    }

    public ArrowSystem(Node collisionNode) {
        this.collisionNode = collisionNode;
    }

    @Override
    public void initialize(AppStateManager stateManager, Application app) {
        super.initialize(stateManager, app);
        entities = this.ed.getEntities(ArrowComponent.class, PositionComponent.class, VelocityComponent.class);
    }

    @Override
    public void update(float tpf) {
        rotCount += tpf;
        rotCount %= FastMath.TWO_PI;
        Quaternion rotation = new Quaternion();
        Quaternion tmpRot = new Quaternion();
        rotation.fromAngles(0, 0, rotCount * 8);
        entities.applyChanges();
        for (Entity e : entities) {
            //Retrieve position and velocity and calc new values
            Vector3f velocity = e.get(VelocityComponent.class).getVelocity().add(gravity.mult(tpf));
            Vector3f position = e.get(PositionComponent.class).getPosition().add(velocity.mult(tpf));

            //Calc new Orientation
            tmpRot.lookAt(velocity, Vector3f.UNIT_Y);
            //Inner rotation of arrow
            tmpRot = tmpRot.mult(rotation);

            //Check for collisions
            CollisionResults results = new CollisionResults();
            Ray ray = new Ray(e.get(PositionComponent.class).getPosition(), velocity);
            collisionNode.collideWith(ray, results);
            //Set new values
            ed.setComponents(e.getId(), new PositionComponent(position),
                    new VelocityComponent(velocity),
                    new RotationComponent(tmpRot.clone()));
            for (CollisionResult last : results) {
                if (last.getGeometry().getUserData("EntityId") != null) {
                    EntityId eId = new EntityId((long) last.getGeometry().getUserData("EntityId"));
                    if (ed.getComponent(eId, SolidComponent.class) != null) {
                        if (last.getDistance() <= velocity.length() * tpf) {
                            //If hit, stop Arrow

                            ed.setComponent(e.getId(), new PositionComponent(last.getContactPoint().clone()));
                            ed.removeComponent(e.getId(), VelocityComponent.class);
                            ed.removeComponent(e.getId(), ArrowComponent.class);
                            break;
                        }
                    }
                }
            }
        }
    }
}
